package dnl.confij.props;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Collection;
import java.util.Properties;
import java.util.Set;
import java.util.Map.Entry;

import dnl.confij.BaseConfigurationSource;
import dnl.confij.ConfigException;
import dnl.confij.ConfigParam;
import dnl.confij.ConfigSection;
import dnl.confij.Configuration;

/**
 * A properties based configuration source.
 * 
 * @author <a href="mailto:daniel.or@gmail.com">Daniel Or</a>
 * 
 */
public class PropertiesConfigurationSource extends BaseConfigurationSource {

	private Properties properties = new Properties();

	private String charset;

	/**
	 * 
	 * Constructs a new <code>PropertiesConfigurationSource</code> using the
	 * given file.
	 * 
	 * @param propertiesFile
	 */
	public PropertiesConfigurationSource(File propertiesFile) {
		super(propertiesFile);
	}

	/**
	 * 
	 * Constructs a new <code>PropertiesConfigurationSource</code> using the
	 * given file and the given charset.
	 * 
	 * @param propertiesFile
	 * @param charset
	 *            a character set that corresponds to the file's encoding.
	 */
	public PropertiesConfigurationSource(File propertiesFile, String charset) {
		super(propertiesFile);
		this.charset = charset;
	}

	@Override
	protected void loadConfigurationImpl(Configuration config)
			throws ConfigException {
		properties.clear();
		try {
			if (charset == null) {
				properties.load(new FileReader(getConfigFile()));
			} else {
				properties.load(new InputStreamReader(new FileInputStream(
						getConfigFile()), charset));
			}
		} catch (Exception e) {
			throw new ConfigException(e);
		}
		Set<Entry<Object, Object>> entrySet = properties.entrySet();
		for (Entry<Object, Object> entry : entrySet) {
			String key = (String) entry.getKey();
			String val = (String) entry.getValue();

			String sectionName = "";
			int ind = key.lastIndexOf('.');

			if (ind > 0) {
				sectionName = key.substring(0, ind);
				ConfigSection cs = config.getOrCreateSection(sectionName);
				config.addSection(cs);
				String paramKey = key.substring(ind + 1);
				cs.setParamValue(paramKey , val);
			}
		}
	}

	@Override
	protected void saveConfigurationImpl(Configuration config)
			throws ConfigException {
		properties.clear();

		Collection<ConfigSection> sections = config.getSections();
		for (ConfigSection section : sections) {
			String sectionKey = section.getName() + ".";
			Collection<ConfigParam> configParameters = section.getConfigParameters();
			for (ConfigParam configParam : configParameters) {
				properties.put(sectionKey + configParam.getName(), configParam.getValue());
			}
		}

		try {
			if (charset == null) {
				properties.store(new FileWriter(getConfigFile()), "");
			} else {
				properties.store(new OutputStreamWriter(new FileOutputStream(
						getConfigFile()), charset), "");

			}
		} catch (IOException e) {
			throw new ConfigException(e);
		}

	}

}
